package com.googlecode.smartgwtmavenplugin.mojo.lifted;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.util.Collection;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.installer.ArtifactInstallationException;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
import org.apache.maven.project.validation.ModelValidationResult;
import org.apache.maven.project.validation.ModelValidator;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;


/**
 * Installs all files in the SmartGWT runtime to the local repository.  Adapted under the Apache 2 license from version 2.3.1 of the 
 * InstallFileMojo at http://maven.apache.org/plugins/maven-install-plugin/.  The original Author's name is preserved to give credit
 * where credit is due, but changes have been made to the original to better suit my own purpose.  Namely, this object's execute 
 * method iterate's over a collection of files, where the original operated on one file at a time keeping details of the file in 
 * member variables.
 * 
 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 * @goal install
 * @execute goal=prepare
 * @requiresProject false
 */
public class InstallMojo extends AbstractInstallMojo {

	/** @parameter property="workdir.unpacked" */
	private File unpacked;
	
    /** @component The component used to validate the user-supplied artifact coordinates. */
    private ModelValidator modelValidator;
	
    /**
     * Resolves Artifacts in the local repository.
     * 
     * @component
     */
    private ArtifactResolver artifactResolver;
    
	/**
	 * 
	 */
	public void execute() throws MojoExecutionException, MojoFailureException {
		
		getLog().info("Scanning directory '" + unpacked.getAbsolutePath() + "' for distribution...");
		
		//for each jar in unpacked dir
		Collection<File> jars = FileUtils.listFiles(unpacked, new String[]{"jar"}, false);
		for (File jar : jars) {
			String base = FilenameUtils.getBaseName(jar.getName());
			install(jar, new File(unpacked, base + ".pom"));
		}
		Collection<File> poms = FileUtils.listFiles(unpacked, new String[]{"xml"}, false);
		for (File pom : poms) {
			String base = FilenameUtils.getBaseName(pom.getName());
			install(pom, pom);
		}
	}
	
	public void install(File file, File pom) throws MojoExecutionException, MojoFailureException {

		Model model = readModel(pom);
		validateArtifactInformation(model);

		String groupId = model.getGroupId();
		String artifactId = model.getArtifactId();
		String version = model.getVersion();
		String packaging = model.getPackaging();
		String classifier = null;
		
		Artifact artifact = artifactFactory.createArtifactWithClassifier(groupId, artifactId, version, packaging, classifier);

		if (! "pom".equals(packaging.toLowerCase())) {
			ArtifactMetadata pomMetadata = new ProjectArtifactMetadata(artifact, pom);
	        artifact.addMetadata(pomMetadata);
		} 
	        
		try {
			installer.install(file, artifact, localRepository);
			installChecksums(artifact);
		} catch (ArtifactInstallationException e) {
			throw new MojoExecutionException("Error installing artifact '" + artifact.getDependencyConflictId() + "'", e);
		}

		String docs = model.getProperties().getProperty("javadoc", "spoon!");
		File javadoc = new File(unpacked, docs);
		if (javadoc.exists()) {
			artifact = artifactFactory.createArtifactWithClassifier(groupId, artifactId, version, "jar", "javadoc");
			try {
				installer.install(javadoc, artifact, localRepository);
				installChecksums(artifact);
			} catch (ArtifactInstallationException e) {
				throw new MojoExecutionException("Error installing API docs " + javadoc, e);
			}
		}
	}

	/**
	 * Parses a POM.
	 * 
	 * @param pomFile
	 *            The path of the POM file to parse, must not be
	 *            <code>null</code>.
	 * @return The model from the POM file, never <code>null</code>.
	 * @throws MojoExecutionException
	 *             If the POM could not be parsed.
	 */
	private Model readModel(File pomFile) throws MojoExecutionException {
		Reader reader = null;
		try {
			reader = ReaderFactory.newXmlReader(pomFile);
			return new MavenXpp3Reader().read(reader);
		} catch (FileNotFoundException e) {
			throw new MojoExecutionException("File not found " + pomFile, e);
		} catch (IOException e) {
			throw new MojoExecutionException("Error reading POM " + pomFile, e);
		} catch (XmlPullParserException e) {
			throw new MojoExecutionException("Error parsing POM " + pomFile, e);
		} finally {
			IOUtil.close(reader);
		}
	}

    /**
     * Validates the user-supplied artifact information.
     *
     * @throws MojoExecutionException If any artifact coordinate is invalid.
     */
    private void validateArtifactInformation(Model model) throws MojoExecutionException {

        ModelValidationResult result = modelValidator.validate( model );

        if ( result.getMessageCount() > 0 ) {
            throw new MojoExecutionException("The artifact information is incomplete or not valid:\n" + result.render( "  " ) );
        }
    }
}